

package org.apache.ocean.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.ocean.CLong;
import org.apache.ocean.CScoreDocument;
import org.apache.ocean.ClusterConstants;
import org.apache.ocean.ClusterUtil;
import org.apache.ocean.DateParser;
import org.apache.ocean.IDVersion;
import org.apache.ocean.IndexSchema;
import org.apache.ocean.OceanQueryParser;
import org.apache.ocean.SearchConfig;
import org.apache.ocean.SearchIndexShard;
import org.apache.ocean.SearchResponse;
import org.apache.ocean.SearchService;
import org.apache.ocean.TimeoutState;
import org.apache.ocean.TransactionID;
import org.apache.ocean.TransactionRecord;
import org.apache.ocean.TransactionRecordRequest;
import org.apache.ocean.XMLUtil;
import org.apache.ocean.name.Node;



/**
 *
 * @author  jason rutherglen
 */
public class RPCServlet extends HttpServlet {
  public static Logger log = Logger.getLogger(RPCServlet.class.getName());
  public SearchService searchService;
  public String thisURL;
  
  public RPCServlet() {
  }
  
  public void init() throws ServletException {
    try {
      searchService = SearchService.getSearchService();
      log.log(Level.INFO, "RPCServlet.init finished");
    } catch (Throwable ex) {
      log.log(Level.SEVERE, "", ex);
    }
  }
  
  private void logIfHigh(long time, String message) {
    if (time > 1000) {
      SearchService.seriousLog.log(Level.SEVERE, "time: "+time+" msg: "+message);
    }
  }
  
  public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
      response.setContentType(ClusterConstants.CONTENT_TYPE_XML);
      URL requestURL = new URL(request.getRequestURL().toString());
      //log.log(Level.INFO, "doGet requestURL: "+requestURL);
      String action = request.getParameter("action");
      if (StringUtils.equals(action, "getsearchconfig")) {
        handleGetSearchConfig(request, response);
        return;
      } else if (StringUtils.equals(action, "getindexschema")) {
        handleGetIndexSchema(request, response);
        return;
      } else if (StringUtils.equals(action, "delete")) {
        handleDelete(request, response);
        return;
      } else if (StringUtils.equals(action, "getnode")) {
        handleGetNode(request, response);
        return;
      } else if (StringUtils.equals(action, "gettransaction")) {
        handleGetTransaction(request, response);
        return;
      } else if (StringUtils.equals(action, "getdocfreq")) {
        handleGetDocFreq(request, response);
        return;
      } else if (StringUtils.equals(action, "getfileslist")) {
        handleGetFilesList(request, response);
        return;
      } else if (StringUtils.equals(action, "getfile")) {
        handleGetFile(request, response);
        return;
      }
    } catch (Throwable throwable) {
      log.log(Level.SEVERE, "", throwable);
      response.setContentType("text/plain");
      sendError(throwable, response);
    }
  }
  
  private File getDirectory(HttpServletRequest request) throws Exception {
    File directory = null;
    String type = request.getParameter("type");
    if (StringUtils.equals("shardfiles", type)) {
      String shardid = request.getParameter("shardid");
      if (StringUtils.isBlank(shardid)) {
        throw new Exception("shardid missing");
      }
      File indexShardsDirectory = searchService.searchConfig.indicesDirectory;
      directory = new File(indexShardsDirectory, shardid);
    } else {
      throw new Exception("unknown type: "+type);
    }
    if (!directory.exists()) {
      throw new Exception("directory does not exist: "+directory.getName());
    }
    return directory;
  }
  
  public void handleGetFile(HttpServletRequest request, HttpServletResponse response) throws Exception {
    File directory = getDirectory(request);
    String filename = request.getParameter("filename");
    if (StringUtils.isBlank(filename)) {
      ClusterUtil.sendError("filename blank", response);
    }
    File file = new File(directory, filename);
    OutputStream output = response.getOutputStream();
    FileInputStream fileInput = new FileInputStream(file);
    IOUtils.copy(fileInput, output);
    fileInput.close();
  }
  
  public void handleGetFilesList(HttpServletRequest request, HttpServletResponse response) throws Exception {
    File directory = null;
    try {
      directory = getDirectory(request);
    } catch (Throwable throwable) {
      ClusterUtil.sendError(throwable.getMessage(), response);
    }
    response.setContentType(ClusterConstants.CONTENT_TYPE_XML);
    PrintWriter writer = response.getWriter();
    File[] files = directory.listFiles();
    org.jdom.Element element = new org.jdom.Element("files");
    for (int x=0; x < files.length; x++) {
      org.jdom.Element fileElement = new org.jdom.Element("file");
      XMLUtil.createTextElement("name", files[x].getName(), fileElement);
      XMLUtil.createTextElement("size", Long.toString(files[x].length()), fileElement);
      Date lastModified = new Date(files[x].lastModified());
      XMLUtil.createTextElement("lastModified", DateParser.formatRFC822(lastModified), fileElement);
      element.addContent(fileElement);
    }
    String xml = XMLUtil.outputElement(element);
    writer.write(xml);
  }
  
  public void handleGetDocFreqPOST(URL requestURL, HttpServletRequest request, HttpServletResponse response) throws Exception {
  }
  
  public void handleGetDocFreq(HttpServletRequest request, HttpServletResponse response) throws Exception {
    response.setContentType(ClusterConstants.CONTENT_TYPE_XML);
    String queryString = request.getParameter("q");
    IndexSchema indexSchema = searchService.getIndexSchema();
    Query query = OceanQueryParser.parse(queryString, indexSchema);
    TimeoutState timeoutState = new TimeoutState();
    Map<Term,AtomicLong> docFreqMap = searchService.getDocumentFrequencies(query, timeoutState);
    PrintWriter writer = response.getWriter();
    SearchResponse searchResponse = new SearchResponse();
    searchResponse.scoreDocuments = new ArrayList<CScoreDocument>(docFreqMap.size());
    for (Map.Entry<Term,AtomicLong> entry : docFreqMap.entrySet()) {
      Term term = entry.getKey();
      AtomicLong freq = entry.getValue();
      Document document = new Document();
      String textReadable = ClusterUtil.indexedToReadable(term.field(), term.text(), indexSchema);
      

    }
    response.setContentType(ClusterConstants.CONTENT_TYPE_XML);
  }
  
  public void handleGetTransactions(HttpServletRequest request, HttpServletResponse response) throws Exception {
    Integer rows = ClusterUtil.parseInteger(request.getParameter("rows"));
    if (rows == null) rows = new Integer(10);
    String[] transactionrecordrequestArray = request.getParameterValues("transactionrecordrequest");
    if (transactionrecordrequestArray == null) {
      ClusterUtil.sendError("transactionrecordrequest missing", response);
      return;
    }
    List<TransactionRecordRequest> transactionRecordRequests = new ArrayList<TransactionRecordRequest>(transactionrecordrequestArray.length);
    for (String string : transactionrecordrequestArray) {
      TransactionRecordRequest transactionRecordRequest = TransactionRecordRequest.parse(string);
      transactionRecordRequests.add(transactionRecordRequest);
    }
    List<TransactionRecord> transactionRecords = searchService.getTransactionRecords(transactionRecordRequests, rows);
    for (TransactionRecord transactionRecord : transactionRecords) {
      
    }
  }
  
  public void handleGetTransaction(HttpServletRequest request, HttpServletResponse response) throws Exception {
    String idString = request.getParameter("id");
    String shardID = request.getParameter("shardid");
    TransactionID id = TransactionID.parse(idString);
    SearchIndexShard searchIndexShard = searchService.getSearchIndexShard(shardID);
    TransactionRecord transactionRecord = searchIndexShard.getTransactionDatabase().findTransactionRecord(id);
    
  }
  
  public void handleDelete(HttpServletRequest request, HttpServletResponse response) throws Exception {
    CLong id = ClusterUtil.parseLong(request.getParameter("id"));
    CLong version = ClusterUtil.parseLong(request.getParameter("version"));
    String shardID = request.getParameter("shardid");
    IDVersion idVersion = new IDVersion(id, version, shardID);
    //searchService.deleteDocumentMaster(idVersion);
  }
  
  public void sendError(Throwable throwable, HttpServletResponse response) throws IOException {
    String stackTrace = ExceptionUtils.getFullStackTrace(throwable);
    PrintWriter writer = response.getWriter();
    writer.print(stackTrace);
  }
  
  public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.setContentType(ClusterConstants.CONTENT_TYPE_XML);
    URL requestURL = new URL(request.getRequestURL().toString());
    log.log(Level.INFO, "doPost requestURL: "+requestURL);
    String path = requestURL.getPath();
    try {
      
    } catch (Throwable throwable) {
      log.log(Level.SEVERE, "", throwable);
      sendError(throwable, response);
    }
  }
  
  public void handleGetNode(HttpServletRequest request, HttpServletResponse response) throws Exception {
    Node node = searchService.createReportableNode();
    String xml = XMLUtil.outputElement(node.toElement());
    response.setContentType(ClusterConstants.CONTENT_TYPE_XML);
    PrintWriter writer = response.getWriter();
    writer.write(xml);
  }
  
  public void handleGetSearchConfig(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //SearchConfig searchConfig = searchService.getSearchConfig();
    //String xml = XMLUtil.outputElement(searchConfig.toElement());
    //response.setContentType(ClusterConstants.CONTENT_TYPE_XML);
    //PrintWriter writer = response.getWriter();
    //writer.write(xml);
  }
  
  public void handleGetIndexSchema(HttpServletRequest request, HttpServletResponse response) throws Exception {
    IndexSchema indexSchema = searchService.getIndexSchema();
    String xml = indexSchema.toXML();
    response.setContentType(ClusterConstants.CONTENT_TYPE_XML);
    PrintWriter writer = response.getWriter();
    writer.write(xml);
  }
  
  
  
  public void printValue(String name, String internalValue, PrintWriter writer) throws Exception {
    SchemaField schemaField = searchService.getIndexSchema().getField(name);
    String value = schemaField.getFieldType().indexedToReadable(internalValue);
    writer.print(value);
  }
}
